home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 April: Mac OS SDK / Dev.CD Apr 99 SDK1.toast / Development Kits / Open Transport 1.3 / Open Transport SDK / Open Tpt Protocol Developer / Samples / Configurators / TMP_CreateConfig.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-30  |  12.8 KB  |  429 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        TMP_CreateConfig.c
  3.  
  4.     Contains:    The non-resident code for our template configurator class
  5.     
  6.                 This code is not intended to implement an actual 
  7.                 working configurator.  It comes with no warranty,
  8.                 express or implied, as to it's suitability for your
  9.                 own configuration implementation.
  10.  
  11. */
  12.  
  13. #ifndef __TMP_CONFIG__
  14. #include "TMP_Config.h"
  15. #endif
  16. #if TMPCONFIG_USES_ASLM
  17.     #include <LibraryManagerUtilities.h>
  18. #else
  19.     #include <CodeFragments.h>
  20. #endif
  21.  
  22. /*******************************************************************************
  23. ** Globals
  24. ********************************************************************************/
  25.  
  26. static TMPConfigurator* gConfigData = NULL;
  27.  
  28. /*
  29.  * Size of preference structures for our various protocol
  30.  * preferences.
  31.  */
  32. static UInt16    gPrefLens[] =
  33. {
  34.     sizeof(Prot1Prefs),
  35.     sizeof(Prot2Prefs),
  36.     sizeof(Prot3Prefs)
  37. };
  38.  
  39. static char* gProtNames[] = { kProtocolList, 0 };
  40.  
  41. /*******************************************************************************
  42. ** ReadMyPreferences
  43. **
  44. ** You must supply this function to read your preferences.
  45. ********************************************************************************/    
  46.  
  47. static OSStatus ReadMyPreferences(MyPreferences **prefs, OTPortRef link_id)
  48. {
  49.     #pragma unused(prefs)
  50.     #pragma unused(link_id)
  51.     return noErr;
  52. }
  53.  
  54. /*******************************************************************************
  55. ** DestroyMyPreferences
  56. **
  57. ** You must supply this function to destroy your preferences.
  58. ********************************************************************************/    
  59.  
  60. static void DestroyMyPreferences(MyPreferences *prefs)
  61. {
  62.     #pragma unused(prefs)
  63. }
  64.  
  65. /*******************************************************************************
  66. ** MyCreateConfiguration
  67. **
  68. ** This is the state machine function that we use to open the control stream.
  69. ********************************************************************************/    
  70.  
  71. static pascal void MyCreateConfiguration(OTStateMachine* sm)
  72. {
  73.     TMPOpenInfo*    info    = (TMPOpenInfo*)OTSMGetClientData(sm);
  74.     AConfiguration*    aCfig    = info->fConfig;
  75.     
  76.     while ( true )
  77.     {
  78.         switch ( OTSMGetState(sm) )
  79.         {
  80.             /*
  81.              * For the purposes of this template, we just assume you have some function
  82.              * that will read your preferences from somewhere.
  83.              */
  84.             case 0:
  85.             {
  86.                 /*
  87.                  * Just in case there are already prefs present, destroy them.
  88.                  */
  89.                 if ( aCfig->fPrefs != NULL )
  90.                 {
  91.                     DestroyMyPreferences(aCfig->fPrefs);
  92.                     aCfig->fPrefs = NULL;
  93.                 }
  94.                 /*
  95.                  * This function reads in the prefs, creates the prefs structure and stores
  96.                  * it in the pointer passed.  If it can't read the prefs, it can either
  97.                  * create a set of default preferences, or just return an error.
  98.                  */
  99.                 sm->fResult = ReadMyPreferences(&aCfig->fPrefs, info->fConfig->fLinkID);
  100.  
  101.                 if ( sm->fResult == kOTNoError )
  102.                     break;
  103.                 /*
  104.                  * Now, we're creating our network layer - we want a separate copy for each link
  105.                  * that we're created over.  Some protocols might want this, and others won't.  For
  106.                  * instance, TCP/IP keeps a single TCP/IP, and routes between all links.  For 
  107.                  * AppleTalk, we treat each stack as linearly independent.  To do this, we need
  108.                  * STREAMS to think that this is a different DDP than all the other DDPs that exist
  109.                  * over other link layers.  To do this, we register DDP as a private pseud-port. 
  110.                  * This gives each copy of DDP over a different link a different name so that STREAMS
  111.                  * believes it's a different driver.
  112.                  */
  113.                 OTSMSetState(sm, 1);
  114.                 /*
  115.                  * Only do this if we don't already have a name, which means we're already registered.
  116.                  */
  117.                 if ( aCfig->fNetworkName[0] == 0 )
  118.                 {
  119.                     OTPortRecord    record;
  120.  
  121.                     OTMemzero(&record, sizeof(record));
  122.                     /*
  123.                      * We're a pseudo-device, so we're going to let Open Transport assign us a
  124.                      * port ref, because we don't care what it is
  125.                      */
  126.                     record.fRef                        = OTCreatePortRef(0, kOTPseudoDevice, 0, 0);
  127.                     /*
  128.                      * Flag that we're a private port so clients scanning the port list know this
  129.                      */
  130.                     record.fInfoFlags                = kOTPortIsPrivate;
  131.                     record.fCapabilities            = 0;
  132.                     /*
  133.                      * Let Open Transport provide us with a port name
  134.                      */
  135.                     record.fPortName[0]                = 0;
  136.                     /*
  137.                      * Set up that we have 1 child port, our link layer.  This allows the
  138.                      * OTIsDependentPort function to realize that we depend on this link
  139.                      * layer.
  140.                      */
  141.                     record.fChildPorts                = &aCfig->fLinkID;
  142.                     record.fNumChildPorts            = 1;
  143.                     /*
  144.                      * Copy in the name of our stream module. For the purposes of illustration,
  145.                      * we assume it's the kProt1ID protocol
  146.                      */
  147.                     OTStrCopy(record.fModuleName, gProtNames[kProt1ID]);
  148.                     /*
  149.                      * Register the port.  If an error - split
  150.                      */
  151.                     sm->fResult = OTRegisterPort(&record, NULL);
  152.                     if ( sm->fResult != kOTNoError )
  153.                         break;
  154.                     /*
  155.                      * Save off our port ref, and the name Open Transport gave us.
  156.                      */
  157.                     aCfig->fOurID = record.fRef;
  158.                     OTStrCopy(aCfig->fNetworkName, record.fPortName);
  159.                 }
  160.                 /*
  161.                  * Now open the stream by our port name.  If it returns true, then the call
  162.                  * is already done, and we should reenter the state machine to keep going.
  163.                  */
  164.                 if ( !OTSMOpenStream(sm, aCfig->fNetworkName, info->fOpenFlags) )
  165.                     return;
  166.                 continue;
  167.             }
  168.             
  169.             case 1:
  170.             {
  171.                 /*
  172.                  * If opening our control stream failed - split
  173.                  * Otherwise, save off the StreamRef.
  174.                  */
  175.                 if ( sm->fResult != kOTNoError )
  176.                     break;
  177.  
  178.                 aCfig->fCtlStream    = (StreamRef)sm->fCookie;
  179.                 
  180.             /*    -----------------------------------------------------------------
  181.                 Get our Preferences and download them to the control Stream.
  182.                 ----------------------------------------------------------------- */
  183.     
  184.                 OTSMSetState(sm, 2);
  185.                 
  186.                 info->fIoctlInfo.ic_cmd        = kMyConfigureIoctl;
  187.                 info->fIoctlInfo.ic_timout    = 15;
  188.                 info->fIoctlInfo.ic_len        = gPrefLens[0];
  189.                 info->fIoctlInfo.ic_dp        = (char*)aCfig->fPrefs->fPrefs[0];
  190.                 if ( !OTSMIoctl(sm, aCfig->fCtlStream, I_STR, (long) &info->fIoctlInfo) )
  191.                     return;
  192.                 continue;
  193.             }
  194.             
  195.             //
  196.             // The following states send more IOCTLs to our network layer to set up the preferences
  197.             //
  198.             #define kPrefsState 1
  199.             
  200.             case 2:
  201.             case 3:
  202.             {
  203.                 size_t state = OTSMGetState(sm);
  204.                 
  205.                 if ( sm->fResult < 0 )
  206.                     break;
  207.  
  208.                 OTSMSetState(sm, state + 1);
  209.                 info->fIoctlInfo.ic_cmd        = kMyConfigureIoctl + state - kPrefsState;
  210.                 info->fIoctlInfo.ic_timout    = 15;
  211.                 info->fIoctlInfo.ic_len        = gPrefLens[state - kPrefsState];
  212.                 info->fIoctlInfo.ic_dp        = (char*)aCfig->fPrefs->fPrefs[state - kPrefsState];
  213.                 if ( !OTSMIoctl(sm, aCfig->fCtlStream, I_STR, (long) &info->fIoctlInfo) )
  214.                     return;
  215.                 continue;
  216.             }
  217.             
  218.             /*
  219.              * Now, let's create the link layer
  220.              */
  221.             case 4:
  222.             {
  223.                 OTSMSetState(sm, 5);
  224.                 if ( sm->fResult < 0 )
  225.                     break;
  226.                 /*
  227.                  * We call OTSMCreateStream instead of OTSMOpenStream because the child may
  228.                  * be arbitrarily complex, and just "opening" the child may be a big mistake.
  229.                  * We let the rest of the Open Transport infrastructure figure out how to
  230.                  * create our child, and just return us the StreamRef.
  231.                  */
  232.                 if ( !OTSMCreateStream(sm, OTCfigGetChild(info->fCfig, 0), info->fOpenFlags) )
  233.                     return;
  234.                 continue;
  235.             }
  236.             
  237.             /*
  238.              * Now, let's I_LINK the driver module under our protocol.  We need to do this as
  239.              * an I_LINK, because if we just push the network layer on top, we don't get the
  240.              * cloning effect that we want.  Remember that you can only bind 1 time to the link
  241.              * layer, and the network layer has to de-multiplex incoming packets to the other
  242.              * copies of the network layer.  Otherwise, each network layer instance would have to
  243.              * bind to the same address to the link layer.  While Open Transport allows this, it
  244.              * would be grossly inefficient.
  245.              */
  246.             case 5:
  247.             {
  248.                 OTSMSetState(sm, 6);
  249.                 if ( sm->fResult != kOTNoError )
  250.                     break;
  251.                 /*
  252.                  * Now link the driver under our control stream.  Note that the
  253.                  * StreamRef of the driver is in sm->fCookie.
  254.                  */
  255.                 info->fTheStream = (StreamRef)sm->fCookie;
  256.                 if ( !OTSMIoctl(sm, aCfig->fCtlStream, I_LINK, (long) info->fTheStream) )
  257.                     return;
  258.             }
  259.             
  260.             /*
  261.              * Check the result of the I_LINK, then close the driver, then create a
  262.              * 2nd stream, where we're going to push our "helper" module (for AppleTalk,
  263.              * this would be the NBP module) over that second stream.
  264.              */
  265.             case 6:
  266.             {
  267.                 OTSMSetState(sm, 7);
  268.                 /*
  269.                  * Be very careful here - we can't check sm->fResult != kOTNoError, since
  270.                  * IOCTLs can return positive values (in the case of I_LINKs, its the muxid).
  271.                  */
  272.                 if ( sm->fResult < 0 )
  273.                     break;
  274.                 /*
  275.                  * Now that the driver is linked, we can close it.  That way, when we
  276.                  * close the control stream, the driver will automatically be closed.
  277.                  * Otherwise, we would have to keep the driver StreamRef around until
  278.                  * we closed down.
  279.                  */
  280.                 OTStreamClose(info->fTheStream);
  281.                 /*
  282.                  * Open a 2nd copy of our network layer.  This is a clone of our
  283.                  * original copy of the protocol.
  284.                  */
  285.                 if ( !OTSMOpenStream(sm, aCfig->fNetworkName, info->fOpenFlags) )
  286.                     return;
  287.                 continue;
  288.             }
  289.             /*
  290.              * Save it as the helper stream, and turn signals on on the control stream, so that
  291.              * we can get event notification
  292.              */
  293.             case 7:
  294.             {
  295.                 OTSMSetState(sm, 8);
  296.                 if ( sm->fResult != kOTNoError )
  297.                     break;
  298.  
  299.                 aCfig->fHelperStream = (StreamRef)sm->fCookie;
  300.  
  301.                 if ( !OTSMIoctl(sm, aCfig->fCtlStream, I_SETSIG,
  302.                                       S_INPUT | S_RDNORM | S_RDBAND | S_HIPRI | S_OUTPUT | S_WRNORM | 
  303.                                       S_WRBAND | S_MSG | S_ERROR | S_HANGUP | S_BANDURG) )
  304.                     return;
  305.                 continue;
  306.             }
  307.             /*
  308.              * Now, we push our helper module onto the 2nd network layer
  309.              */
  310.             case 8:
  311.             {
  312.                 OTSMSetState(sm, 9);
  313.                 if ( sm->fResult != kOTNoError )
  314.                     break;
  315.                 /*
  316.                  * Install our notifier into the stream, then do the push onto the
  317.                  * helper stream.
  318.                  * Note that the "controller" code put the proc pointer into the
  319.                  * TMPOpenInfo structure so that we can install the notifier, even though
  320.                  * the "controller" is the one to get notifications.
  321.                  */
  322.                 OTStreamInstallNotifier(aCfig->fCtlStream, info->fNotifyProc, aCfig);
  323.                 if ( !OTSMIoctl(sm, aCfig->fHelperStream, I_PUSH, (long) gProtNames[kProt3ID]) )
  324.                     return;
  325.                 continue;
  326.             }
  327.             /*
  328.              * Here, the helper push is done.  We are fully configured if it worked.
  329.              */
  330.             case 9:
  331.             {
  332.                 if ( sm->fResult < 0 )
  333.                     break;
  334.  
  335.                 //
  336.                 // Update our status and store the configuration onto our global list
  337.                 // of configurations.
  338.                 //
  339.                 aCfig->fStatus = kIsInUse;
  340.                 OTAddFirst(&gConfigData->fGlobal->fConfigs, &aCfig->fMyLink);
  341.                 sm->fResult    = kOTNoError;
  342.                 sm->fCode    = kStreamOpenEvent;
  343.                 /*
  344.                  * Complete the state machine back to our client
  345.                  */
  346.                 OTSMPopCallback(sm);
  347.                 OTSMComplete(sm);
  348.                 return;
  349.             }
  350.             
  351.         }
  352.         //
  353.         // If we break out of the switch - an error occurred and the fResult
  354.         // field is already filled out.  Make sure the code is a kStreamOpenEvent
  355.         // and complete to our client (which is our controller library).
  356.         //
  357.         sm->fCode    = kStreamOpenEvent;
  358.         OTSMPopCallback(sm);
  359.         OTSMComplete(sm);
  360.         return;
  361.     }
  362. }
  363.  
  364. /*******************************************************************************
  365. ** OTCreateMyConfiguration
  366. **
  367. ** This is the function we export to the other part of our configurator.  It is
  368. ** code we only need while we're plumbing.  If the code is small, there is
  369. ** probably no reason to split it out into a separate shared library, but we've
  370. ** done it for illustration's sake.
  371. ********************************************************************************/
  372.  
  373. Boolean OTCreateMyConfiguration(TOTConfigurator* cfigor, OTStateMachine* sm)
  374. {
  375.     TMPConfigurator* data = (TMPConfigurator*)OTGetConfiguratorUserData(cfigor);
  376.     TMPOpenInfo*     info = (TMPOpenInfo*)OTSMGetClientData(sm);
  377.     OTConfiguration* kid = OTCfigGetChild(info->fCfig, 0);
  378.     /*
  379.      * Save off the configuration info
  380.      */
  381.     gConfigData = data;
  382.     /*
  383.      * Get our child, and set up our link ID.  Of course, if we're a link layer,
  384.      * getting our child is usually not done, but then, for a link layer, this
  385.      * 3rd library is not often needed anyway.
  386.      */
  387.     info->fConfig->fLinkID = OTCfigGetPortRef(kid);
  388.  
  389.     return OTSMCallStateProc(sm, MyCreateConfiguration, 0);
  390. }
  391.  
  392. /*******************************************************************************
  393. ** This is our init and teardown routine
  394. ********************************************************************************/
  395.  
  396. pascal void TeardownTMPCreateConfig(void)
  397. {
  398.     CloseOpenTransport();
  399. }
  400.  
  401. #if GENERATING68K
  402.     #pragma segment A5Init
  403. #endif
  404.  
  405. #if TMPCONFIG_USES_CFM
  406.  
  407.     pascal OSErr InitTMPCreateConfig(CFragInitBlock* ibp)
  408.     {
  409.         #pragma unused(ibp)
  410.         return InitOpenTransport();
  411.     }
  412.  
  413. #else
  414.  
  415.     void InitTMPCreateConfig()
  416.     {
  417.         OSStatus err = InitOpenTransport();
  418.         if ( err != kOTNoError )
  419.         {
  420.             Fail(err, NULL);
  421.         }
  422.     }
  423.  
  424. #endif
  425.  
  426. #if GENERATING68K
  427.     #pragma segment Main
  428. #endif
  429.